#include <stdio.h>
#include <stdlib.h>
#include "mystack.h"
#include <exception>

template <typename T>
stack<T>::stack( )
	    : count (0), top(0)
{

}

template <typename T>
stack<T>::~stack()
{
	if (top != 0)
	{
		while ( top->next != 0 )
		{
			top = top->next;	
			delete top->prev;
			top->prev = 0;
		}
		delete top;
	}
}

template <typename T>
void stack<T>::stack_push(T value)
{
#ifdef _DEBUG
	try
	{
		stack_Ok();
	}
	catch(exception& e)
	{
		cout<<e.what()<<endl;
		stack_dump();
		exit(1);
	}
#endif
	try
	{
		Elem<T>* val = new Elem<T>(0,0,value);
	
		if( top != 0 )
		{
			top->prev = val;
			val->next = top;
		}
		top = val;
		count++;                   // increasing count
	
	}
	catch(...)
	{
		throw std::runtime_error("Pushing into full stack");
	
	}
	
}


template <typename T>
T stack<T>::stack_pop()
{
#ifdef _DEBUG
	try
	{
		stack_Ok();
	}
	catch(exception& e)
	{
		cout<<e.what()<<endl;
		stack_dump();
		exit(1);
	}
#endif
	if(count == 0)
		throw std::runtime_error("Popping empty stack");

	T a = top->value;                // saving value in the temporary variable
	if (count != 1)
	{
		top = top->next;                 // changing value of pointer
		top->prev->next = 0;             // cleaning
		top->prev->prev = 0;             // cleaning
		delete top->prev;   
		top->prev = 0;	                  
	}   
	else
	{
		delete top;
		top = 0;
	}
	count--;						   // decrementing
	return a;
}

template <typename T>
void stack<T>::stack_Ok( )
{
	
	if ( count < 0)
		throw std::overflow_error("Negative element count");
	if (((count == 0) && (top != 0))   ||  ((count != 0) && (top == 0)))
		throw std::runtime_error("Count and top mismatch");
	if( top != 0  )
	{
		Elem<T>* pointer = top;
		int counter_new = 0;
		if( pointer->prev != 0 )
			throw std::runtime_error("invalid top element (prev != 0)");	
		while( (counter_new < (count-1)) && (pointer->next != 0))
		{
			if( pointer != pointer->next->prev ) 
				throw std::runtime_error("Invalid linking in stack");
			pointer = pointer->next;
			counter_new++;
		}
		if( counter_new != (count-1) )
			throw std::runtime_error("invalid element count");
	}

}

template <typename T>
void stack<T>::stack_dump( )
{
	cout<<"counter - "<<count<<endl;
	cout<<"top - "<<top<<endl;
	Elem<T>* pointer = top;
	while( pointer != 0 )
	{
		cout<<"next - "<<pointer->next<<endl;
		cout<<"prev - "<<pointer->prev<<endl;
		cout<<"value - "<<pointer->value<<endl;
		pointer = pointer->next;
	}



	
}

